<template>
  <basic-container>
    <avue-crud :option="option"
               :table-loading="loading"
               :data="data"
               :page.sync="page"
               :permission="permissionList"
               :before-open="beforeOpen"
               v-model="form"
               ref="crud"
               @row-del="rowDel"
               @search-change="searchChange"
               @search-reset="searchReset"
               @selection-change="selectionChange"
               @current-change="currentChange"
               @size-change="sizeChange"
               @refresh-change="refreshChange"
               @on-load="onLoad">
      <template slot="menuLeft">
        <el-button type="primary" size="small" plain  v-if="permission.attach_upload"  icon="el-icon-upload2" @click="handleUpload">上 传</el-button>
      </template>
      <template slot-scope="scope" slot="menu">
        <el-button type="text"  size="small"  @click="handleDownload(scope.row)">下载 </el-button>

        <el-button type="text"  size="small"  @click="startModule(scope.row)">启动 </el-button>
      </template>
      <template slot-scope="{row}"  slot="attachSize">
        <el-tag>{{`${row.attachSize} KB`}}</el-tag>
      </template>
    </avue-crud>
    <el-dialog title="升级包上传"  append-to-body  :visible.sync="attachBox"  width="800px">
      <avue-form v-model="attachForm" :option="attachOption"  @submit="uploadFile">
        <template slot="attachFile">
          <el-upload
            action="#"
            accept=".zip" 
            :auto-upload="false" 
            :multiple="false"
            :file-list="fileList"
            :on-exceed="() => this.$message.error('只能选择一个文件')"
            :on-change="(file)=>{this.attachForm.attachFile=file}"
            :limit="1">
            <el-button slot="trigger" type="primary">选取文件</el-button>
            <div slot="tip" class="el-upload__tip">只能上传zip文件，且不超过300Mb</div>
          </el-upload>
        </template> 
        
      </avue-form>
    </el-dialog>
  </basic-container>
</template>

<script>
  import * as api from "@/api/upgrade/package";
  import {mapGetters} from "vuex"; 
  export default {
    data() {
      return {
        shardSize: 10 * 1024 * 1024, 
        uploadBegin:0,
        fileParam:{},
        checkInterval:null,
        shardData:[],

        form: {},
        query: {},
        loading: true,
        page: {
          pageSize: 10,
          currentPage: 1,
          total: 0
        },
        attachBox: false, 
        selectionList: [],
        option: {
          height: 'auto',
          calcHeight: 30,
          tip: false,
          searchShow: true,
          searchMenuSpan: 6,
          border: true,
          index: true,
          viewBtn: true,
          selection: true, 
          dialogClickModal: false,
          column: [ 
            {
              label: "模块",
              prop: "moduleName",
              search: true
            },
            {
              label: "升级包名",
              prop: "originalName",
              search: true
            },
            {
              label: "上传时间",
              prop: "createTime",
            },
            {
              label: "备注",
              prop: "remark"
            }
          ]
        },
        data: [],
        attachForm: {configId:'',attachFile:null},
        fileList:[],
        attachOption: {
          submitBtn: true,
          emptyBtn: false,
          column: [
            {
              label: '模块',
              prop: 'configId', 
              type:'select',
              dicUrl:"/api/packageFrontConfig/dicList",
              props: {
                label: "configName",
                value: "configId"
              },
              rules: [
                {
                  required: true,
                  message: "请选择模块",
                  trigger: "blur"
                }
              ]
            },
            {
              label: '上传',
              prop: 'attachFile',  
              formslot: true,
              rules: [
                {
                  required: true,
                  message: "请选择文件",
                  trigger: "blur"
                }
              ]
            }
          ]
        }
      };
    },
    computed: {
      ...mapGetters(["permission"]),
      permissionList() {
        return {
          addBtn: false,
          editBtn: false,
          viewBtn: false,
          delBtn: false
        };
      },
      ids() {
        let ids = [];
        this.selectionList.forEach(ele => {
          ids.push(ele.id);
        });
        return ids.join(",");
      }
    },
    mounted() {  
    },
    methods: {
      async recursionUpload(param, file, startTime) {
          //FormData私有类对象，访问不到，可以通过get判断值是否传进去  
          let key = param.key;
          let shardIndex = param.shardIndex;
          let shardTotal = param.shardTotal;
          let shardSize = param.shardSize;
          let size = param.size;
          let batchId = param.batchId;
          let fileName = param.fileName;
          let uploadType = param.uploadType; 
          let moduleName = param.moduleName; 
          let suffix = param.suffix;  
          let fileShard = this.getFileShard(shardIndex, shardSize, file); 
          //param.append("file", fileShard);//文件切分后的分片
          //param.file = fileShard;
          let totalParam = new FormData();
          totalParam.append('file', fileShard);
          totalParam.append("uploadType", uploadType);
          totalParam.append("moduleName", moduleName);
          totalParam.append("batchId", batchId);
          totalParam.append("key", key);
          totalParam.append("shardIndex", shardIndex);
          totalParam.append("shardSize", shardSize);
          totalParam.append("shardTotal", shardTotal);
          totalParam.append("size", size);
          totalParam.append("fileName", fileName);
          totalParam.append("suffix", suffix);
          let config = {
              //添加请求头
              headers: {"Content-Type": "multipart/form-data"}
          }; 
          var res = await this.$http.post("/api/package/manage/uploadShard", totalParam, config)

          var resData = res.data;
          if (resData.success) {
                this.shardData[shardIndex -1] = true;
                console.log("共"+shardTotal+"片，分片"+shardIndex+"上传成功，耗时："+(new Date().getTime() - startTime));
          } else {
              console.log("分片"+shardIndex+"上传失败")
          }

      },

      async handUpLoad(moduleName,file) {  
          //文件名称和格式，方便后台合并的时候知道要合成什么格式
          let fileName = file.name;
          let suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
          
          
          // 文件分片
          // let shardSize = 10 * 1024 * 1024;    //以10MB为一个分片
          // let shardSize = 50 * 1024;    //以50KB为一个分片
          let shardSize = this.shardSize; 
          let size = file.size;
          let shardTotal = Math.ceil(size / shardSize); //总片数 
          // 生成文件标识，标识多次上传的是不是同一个文件
          let name = file.name;
          let idx = name.lastIndexOf(".");
          name = name.substring(0,idx);
          let key = new Date().getTime()+"_"+name;                
          this.shardData = [];
          this.uploadBegin = new Date().getTime(); 
          let batchId = new Date().toISOString().replace(/T/, '').replace(/\..+/, ''); 
          this.fileParam = {
              moduleName: moduleName,
              batchId: batchId,
              uploadType:'front',
              shardSize: shardSize,
              shardTotal: shardTotal,
              key: key,
              fileName: fileName,
          };
          for(var shardIndex=1;shardIndex<=shardTotal;shardIndex++){
              this.shardData.push(false);
              let param = {
                  moduleName: moduleName,
                  uploadType:'front',
                  batchId: batchId,
                  key: key,
                  shardIndex: shardIndex,
                  shardSize: shardSize,
                  shardTotal: shardTotal,
                  size: size,
                  fileName: fileName,
                  suffix: suffix
              }                    
              this.recursionUpload(param,file,new Date().getTime());
          }        
          this.checkInterval = window.setInterval(this.checkComplete,1000);
      },
      async margeComplete(){
          let config = {
              //添加请求头
              headers: {"Content-Type": "application/json"}
          };
          this.$http.post("/api/package/manage/uploadMerge", this.fileParam, config).then(res=>{ 
            var resData = res.data;
            this.loading = false
            this.attachBox = false; 
            if (resData.success) {
                console.log("文件合并成功,共耗时："+(new Date().getTime() - this.uploadBegin));
                this.onLoad(this.page);
            } else {
                console.log("文件合并失败");          
            }
          }).catch(()=>{
            this.$message.error('文件合并异常') 
          }) 
          
      },
      checkComplete(){
          var that = this;           
          var success = true;
          for(let idx = 0; idx < that.shardData.length; idx++) {
              if(!that.shardData[idx]){
                  success = false;
                  break;
              }                        
          }
          if(success){                   
              console.log("上传完成,耗时："+(new Date().getTime() - this.uploadBegin)); 
              window.clearInterval(this.checkInterval);
              this.margeComplete();
              
          }
      },

      getFileShard(shardIndex, shardSize, file) { 
          let start = (shardIndex - 1) * shardSize;    //当前分片起始位置
          let end = Math.min(file.size, start + shardSize); //当前分片结束位置
          let fileShard = file.slice(start, end); //从文件中截取当前的分片数据
          return fileShard;
      },


      startModule(row){
         this.$confirm("确定重启该服务?", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        })
        .then(() => { 
          return api.frontStartModule(row);
        })
        .catch(()=>{}) // 添加错误捕获
        .then((res) => {  
          this.onLoad(this.page);
          if(res && res.data && res.data.msg){
            this.$message({
              type: "success",
              message: res.data.msg
            });
          }                    
        });
      },
      handleUpload() {  
        this.attachBox = true; 
        this.loading = false;
        this.attachForm = {configId:'',attachFile:null};
        this.fileList = [];
      },
      uploadFile(form,done) { 
        this.loading = true; 
        if(!this.attachForm.configId){
          this.loading = false;
          this.$message({
            type: 'error',
            message: '请选择模块!',
          });
          return;
        }
        if(!this.attachForm.attachFile || !this.attachForm.attachFile.raw){
          this.loading = false;
          this.$message({
            type: 'error',
            message: '请选择文件!',
          });
          return;
        }
        this.handUpLoad(this.attachForm.configId,this.attachForm.attachFile.raw); 
        this.attachBox = false; 
        this.attachForm.attachFile = null;
        done();
      },  
      handleDownload(row) {
        window.open(`${row.link}`);
      },
      rowDel(row) {
        console.log(row);
      }, 
      beforeOpen(done) {        
        done();
      },
      searchReset() {
        this.query = {};
        this.onLoad(this.page);
      },
      searchChange(params, done) {
        this.query = params;
        this.page.currentPage = 1;
        this.onLoad(this.page, params);
        done();
      },

      selectionChange(list) {
        this.selectionList = list;
      },
      selectionClear() {
        this.selectionList = [];
        this.$refs.crud.toggleSelection();
      },
      currentChange(currentPage) {
        this.page.currentPage = currentPage;
      },
      sizeChange(pageSize) {
        this.page.pageSize = pageSize;
      },
      refreshChange() {
        this.onLoad(this.page, this.query);
      },
      onLoad(page, params = {}) {
        this.loading = true;
        api.getFrontPage(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => { 
          const data = res.data.data;
          this.page.total = data.total;
          this.data = data.records;
          this.loading = false;
          this.selectionClear();
        });
      }
    }
  };
</script>

<style>
</style>
